有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java并发多线程安全发布实例

Java并发在实践中表示,通过将一个有效的不可变对象(例如,一个您构建的、永远不会再更改的日期对象)粘贴到一个同步集合中,您可以安全地发布它,如下所示(摘自本书第53页):

public Map<String, Date> lastLogin =
    Collections.synchronizedMap(new HashMap<String, Date>())

我知道,一旦放入这个同步映射中,放入这个映射中的任何日期对象都是可见的(至少在其初始但完全构造的状态下),但只有当其他线程能够获得对这个映射对象的引用时

由于引用字段lastLogin没有保证可见性的字段属性(final、volatile、guarded或由静态初始值设定项初始化),我认为映射本身可能不会以完全构造的状态显示给其他线程,因此本末倒置。还是我错过了什么


共 (1) 个答案

  1. # 1 楼答案

    您的怀疑有一半是对的,因为lastLogin的值不能保证对其他线程可见。因为lastLogin不是volatilefinal,所以另一个线程可以将其读取为null

    但是,您不必担心其他线程会看到地图的不完整版本Collections.synchronizedMap(...)返回带有final字段的a private class实例JLS section 17.5说:

    The usage model for final fields is a simple one: Set the final fields for an object in that object's constructor; and do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields.

    SynchronizedMap遵循这些规则,因此另一个读取lastLogin的线程将要么读取null或者对完全构造的映射的引用,而不是对不完整或不安全的映射版本的引用